<?php
/**
 * ~ class.phpmailer.php
 * .---------------------------------------------------------------------------.
 * |  Software: PHPMailer - PHP email class                                    |
 * |   Version: 2.0.3                                                          |
 * |   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
 * |      Info: http://phpmailer.sourceforge.net                               |
 * |   Support: http://sourceforge.net/projects/phpmailer/                     |
 * | ------------------------------------------------------------------------- |
 * |    Author: Andy Prevost (project admininistrator)                         |
 * |    Author: Brent R. Matzelle (original founder)                           |
 * | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.               |
 * | Copyright (c) 2001-2003, Brent R. Matzelle                                |
 * | ------------------------------------------------------------------------- |
 * |   License: Distributed under the Lesser General Public License (LGPL)     |
 * |            http://www.gnu.org/copyleft/lesser.html                        |
 * | This program is distributed in the hope that it will be useful - WITHOUT  |
 * | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
 * | FITNESS FOR A PARTICULAR PURPOSE.                                         |
 * | ------------------------------------------------------------------------- |
 * | We offer a number of paid services (www.codeworxtech.com):                |
 * | - Web Hosting on highly optimized fast and secure servers                 |
 * | - Technology Consulting                                                   |
 * | - Oursourcing (highly qualified programmers and graphic designers)        |
 * '---------------------------------------------------------------------------'
 * 
 * /**
 * PHPMailer - PHP email transport class
 * 
 * @package PHPMailer
 * @author Andy Prevost 
 * @copyright 2004 - 2008 Andy Prevost
 */

class PHPMailer{ 
	// ///////////////////////////////////////////////
	// PROPERTIES, PUBLIC
	// ///////////////////////////////////////////////
	/**
	 * Email priority (1 = High, 3 = Normal, 5 = low).
	 * 
	 * @var int 
	 */
	var $Priority = 3;

	/**
	 * Sets the CharSet of the message.
	 * 
	 * @var string 
	 */
	var $CharSet = 'utf-8'; //'iso-8859-1';
	/**
	 * Sets the Content-type of the message.
	 * 
	 * @var string 
	 */
	var $ContentType = 'text/plain';

	/**
	 * Sets the Encoding of the message. Options for this are "8bit",
	 * "7bit", "binary", "base64", and "quoted-printable".
	 * 
	 * @var string 
	 */
	var $Encoding = '8bit';

	/**
	 * Holds the most recent mailer error message.
	 * 
	 * @var string 
	 */
	var $ErrorInfo = '';

	/**
	 * Sets the From email address for the message.
	 * 
	 * @var string 
	 */
	var $From = 'root@localhost';

	/**
	 * Sets the From name of the message.
	 * 
	 * @var string 
	 */
	var $FromName = 'Root User';

	/**
	 * Sets the Sender email (Return-Path) of the message.  If not empty,
	 * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
	 * 
	 * @var string 
	 */
	var $Sender = '';

	/**
	 * Sets the Subject of the message.
	 * 
	 * @var string 
	 */
	var $Subject = '';

	/**
	 * Sets the Body of the message.  This can be either an HTML or text body.
	 * If HTML then run IsHTML(true).
	 * 
	 * @var string 
	 */
	var $Body = '';

	/**
	 * Sets the text-only body of the message.  This automatically sets the
	 * email to multipart/alternative.  This body can be read by mail
	 * clients that do not have HTML email capability such as mutt. Clients
	 * that can read HTML will view the normal Body.
	 * 
	 * @var string 
	 */
	var $AltBody = '';

	/**
	 * Sets word wrapping on the body of the message to a given number of
	 * characters.
	 * 
	 * @var int 
	 */
	var $WordWrap = 0;

	/**
	 * Method to send mail: ("mail", "sendmail", or "smtp").
	 * 
	 * @var string 
	 */
	var $Mailer = 'mail';

	/**
	 * Sets the path of the sendmail program.
	 * 
	 * @var string 
	 */
	var $Sendmail = '/usr/sbin/sendmail';

	/**
	 * Path to PHPMailer plugins.  This is now only useful if the SMTP class
	 * is in a different directory than the PHP include path.
	 * 
	 * @var string 
	 */
	var $PluginDir = '';

	/**
	 * Holds PHPMailer version.
	 * 
	 * @var string 
	 */
	var $Version = "2.0.3";

	/**
	 * Sets the email address that a reading confirmation will be sent.
	 * 
	 * @var string 
	 */
	var $ConfirmReadingTo = '';

	/**
	 * Sets the hostname to use in Message-Id and Received headers
	 * and as default HELO string. If empty, the value returned
	 * by SERVER_NAME is used or 'localhost.localdomain'.
	 * 
	 * @var string 
	 */
	var $Hostname = '';

	/**
	 * Sets the message ID to be used in the Message-Id header.
	 * If empty, a unique id will be generated.
	 * 
	 * @var string 
	 */
	var $MessageID = ''; 
	// ///////////////////////////////////////////////
	// PROPERTIES FOR SMTP
	// ///////////////////////////////////////////////
	/**
	 * Sets the SMTP hosts.  All hosts must be separated by a
	 * semicolon.  You can also specify a different port
	 * for each host by using this format: [hostname:port]
	 * (e.g. "smtp1.example.com:25;smtp2.example.com").
	 * Hosts will be tried in order.
	 * 
	 * @var string 
	 */
	var $Host = 'localhost';

	/**
	 * Sets the default SMTP server port.
	 * 
	 * @var int 
	 */
	var $Port = 25;

	/**
	 * Sets the SMTP HELO of the message (Default is $Hostname).
	 * 
	 * @var string 
	 */
	var $Helo = '';

	/**
	 * Sets connection prefix.
	 * Options are "", "ssl" or "tls"
	 * 
	 * @var string 
	 */
	var $SMTPSecure = "";

	/**
	 * Sets SMTP authentication. Utilizes the Username and Password variables.
	 * 
	 * @var bool 
	 */
	var $SMTPAuth = false;

	/**
	 * Sets SMTP username.
	 * 
	 * @var string 
	 */
	var $Username = '';

	/**
	 * Sets SMTP password.
	 * 
	 * @var string 
	 */
	var $Password = '';

	/**
	 * Sets the SMTP server timeout in seconds. This function will not
	 * work with the win32 version.
	 * 
	 * @var int 
	 */
	var $Timeout = 10;

	/**
	 * Sets SMTP class debugging on or off.
	 * 
	 * @var bool 
	 */
	var $SMTPDebug = false;

	/**
	 * Prevents the SMTP connection from being closed after each mail
	 * sending.  If this is set to true then to close the connection
	 * requires an explicit call to SmtpClose().
	 * 
	 * @var bool 
	 */
	var $SMTPKeepAlive = false;

	/**
	 * Provides the ability to have the TO field process individual
	 * emails, instead of sending to entire TO addresses
	 * 
	 * @var bool 
	 */
	var $SingleTo = false; 
	// ///////////////////////////////////////////////
	// PROPERTIES, PRIVATE
	// ///////////////////////////////////////////////
	var $smtp = null;
	var $to = array();
	var $cc = array();
	var $bcc = array();
	var $ReplyTo = array();
	var $attachment = array();
	var $CustomHeader = array();
	var $message_type = '';
	var $boundary = array();
	var $language = array();
	var $error_count = 0;
	var $LE = "\r\n";
	var $sign_cert_file = "";
	var $sign_key_file = "";
	var $sign_key_pass = ""; 
	// ///////////////////////////////////////////////
	// METHODS, VARIABLES
	// ///////////////////////////////////////////////
	/**
	 * Sets message type to HTML.
	 * 
	 * @param bool $bool 
	 * @return void 
	 */
	function IsHTML($bool){
		if ($bool == true){
			$this -> ContentType = 'text/html';
		}else{
			$this -> ContentType = 'text/plain';
		}
	}

	/**
	 * Sets Mailer to send message using SMTP.
	 * 
	 * @return void 
	 */
	function IsSMTP(){
		$this -> Mailer = 'smtp';
	}

	/**
	 * Sets Mailer to send message using PHP mail() function.
	 * 
	 * @return void 
	 */
	function IsMail(){
		$this -> Mailer = 'mail';
	}

	/**
	 * Sets Mailer to send message using the $Sendmail program.
	 * 
	 * @return void 
	 */
	function IsSendmail(){
		$this -> Mailer = 'sendmail';
	}

	/**
	 * Sets Mailer to send message using the qmail MTA.
	 * 
	 * @return void 
	 */
	function IsQmail(){
		$this -> Sendmail = '/var/qmail/bin/sendmail';
		$this -> Mailer = 'sendmail';
	} 
	// ///////////////////////////////////////////////
	// METHODS, RECIPIENTS
	// ///////////////////////////////////////////////
	/**
	 * Adds a "To" address.
	 * 
	 * @param string $address 
	 * @param string $name 
	 * @return void 
	 */
	function AddAddress($address, $name = ''){
		$cur = count($this -> to);
		$this -> to[$cur][0] = trim($address);
		$this -> to[$cur][1] = $name;
	}

	/**
	 * Adds a "Cc" address. Note: this function works
	 * with the SMTP mailer on win32, not with the "mail"
	 * mailer.
	 * 
	 * @param string $address 
	 * @param string $name 
	 * @return void 
	 */
	function AddCC($address, $name = ''){
		$cur = count($this -> cc);
		$this -> cc[$cur][0] = trim($address);
		$this -> cc[$cur][1] = $name;
	}

	/**
	 * Adds a "Bcc" address. Note: this function works
	 * with the SMTP mailer on win32, not with the "mail"
	 * mailer.
	 * 
	 * @param string $address 
	 * @param string $name 
	 * @return void 
	 */
	function AddBCC($address, $name = ''){
		$cur = count($this -> bcc);
		$this -> bcc[$cur][0] = trim($address);
		$this -> bcc[$cur][1] = $name;
	}

	/**
	 * Adds a "Reply-To" address.
	 * 
	 * @param string $address 
	 * @param string $name 
	 * @return void 
	 */
	function AddReplyTo($address, $name = ''){
		$cur = count($this -> ReplyTo);
		$this -> ReplyTo[$cur][0] = trim($address);
		$this -> ReplyTo[$cur][1] = $name;
	} 
	// ///////////////////////////////////////////////
	// METHODS, MAIL SENDING
	// ///////////////////////////////////////////////
	/**
	 * Creates message and assigns Mailer. If the message is
	 * not sent successfully then it returns false.  Use the ErrorInfo
	 * variable to view description of the error.
	 * 
	 * @return bool 
	 */
	function Send(){
		$header = '';
		$body = '';
		$result = true;

		if ((count($this -> to) + count($this -> cc) + count($this -> bcc)) < 1){
			$this -> SetError($this -> Lang('provide_address'));
			return false;
		}

		/**
		 * Set whether the message is multipart/alternative
		 */
		if (!empty($this -> AltBody)){
			$this -> ContentType = 'multipart/alternative';
		}

		$this -> error_count = 0; // reset errors
		$this -> SetMessageType();
		$header .= $this -> CreateHeader();
		$body = $this -> CreateBody();

		if ($body == ''){
			return false;
		}

		/**
		 * Choose the mailer
		 */
		switch ($this -> Mailer){
			case 'sendmail':
				$result = $this -> SendmailSend($header, $body);
				break;
			case 'smtp':
				$result = $this -> SmtpSend($header, $body);
				break;
			case 'mail':
				$result = $this -> MailSend($header, $body);
				break;
			default:
				$result = $this -> MailSend($header, $body);
				break; 
				// $this->SetError($this->Mailer . $this->Lang('mailer_not_supported'));
				// $result = false;
				// break;
		}

		return $result;
	}

	/**
	 * Sends mail using the $Sendmail program.
	 * 
	 * @access private 
	 * @return bool 
	 */
	function SendmailSend($header, $body){
		if ($this -> Sender != ''){
			$sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this -> Sendmail), escapeshellarg($this -> Sender));
		}else{
			$sendmail = sprintf("%s -oi -t", escapeshellcmd($this -> Sendmail));
		}

		if (!@$mail = popen($sendmail, 'w')){
			$this -> SetError($this -> Lang('execute') . $this -> Sendmail);
			return false;
		}

		fputs($mail, $header);
		fputs($mail, $body);

		$result = pclose($mail);
		if (version_compare(phpversion(), '4.2.3') == -1){
			$result = $result >> 8 &0xFF;
		}
		if ($result != 0){
			$this -> SetError($this -> Lang('execute') . $this -> Sendmail);
			return false;
		}
		return true;
	}

	/**
	 * Sends mail using the PHP mail() function.
	 * 
	 * @access private 
	 * @return bool 
	 */
	function MailSend($header, $body){
		$to = '';
		for($i = 0; $i < count($this -> to); $i++){
			if ($i != 0){
				$to .= ', ';
			}
			$to .= $this -> AddrFormat($this -> to[$i]);
		}

		$toArr = split(',', $to);

		$params = sprintf("-oi -f %s", $this -> Sender);
		if ($this -> Sender != '' && strlen(ini_get('safe_mode')) < 1){
			$old_from = ini_get('sendmail_from');
			ini_set('sendmail_from', $this -> Sender);
			if ($this -> SingleTo === true && count($toArr) > 1){
				foreach ($toArr as $key => $val){
					$rt = @mail($val, $this -> EncodeHeader($this -> SecureHeader($this -> Subject)), $body, $header, $params);
				}
			}else{
				$rt = @mail($to, $this -> EncodeHeader($this -> SecureHeader($this -> Subject)), $body, $header, $params);
			}
		}else{
			if ($this -> SingleTo === true && count($toArr) > 1){
				foreach ($toArr as $key => $val){
					$rt = @mail($val, $this -> EncodeHeader($this -> SecureHeader($this -> Subject)), $body, $header, $params);
				}
			}else{
				$rt = @mail($to, $this -> EncodeHeader($this -> SecureHeader($this -> Subject)), $body, $header);
			}
		}

		if (isset($old_from)){
			ini_set('sendmail_from', $old_from);
		}

		if (!$rt){
			$this -> SetError($this -> Lang('instantiate'));
			return false;
		}

		return true;
	}

	/**
	 * Sends mail via SMTP using PhpSMTP (Author:
	 * Chris Ryan).  Returns bool.  Returns false if there is a
	 * bad MAIL FROM, RCPT, or DATA input.
	 * 
	 * @access private 
	 * @return bool 
	 */
	function SmtpSend($header, $body){
		include_once($this -> PluginDir . 'class.smtp.php');
		$error = '';
		$bad_rcpt = array();

		if (!$this -> SmtpConnect()){
			return false;
		}

		$smtp_from = ($this -> Sender == '') ? $this -> From : $this -> Sender;
		if (!$this -> smtp -> Mail($smtp_from)){
			$error = $this -> Lang('from_failed') . $smtp_from;
			$this -> SetError($error);
			$this -> smtp -> Reset();
			return false;
		}

		/**
		 * Attempt to send attach all recipients
		 */
		for($i = 0; $i < count($this -> to); $i++){
			if (!$this -> smtp -> Recipient($this -> to[$i][0])){
				$bad_rcpt[] = $this -> to[$i][0];
			}
		}
		for($i = 0; $i < count($this -> cc); $i++){
			if (!$this -> smtp -> Recipient($this -> cc[$i][0])){
				$bad_rcpt[] = $this -> cc[$i][0];
			}
		}
		for($i = 0; $i < count($this -> bcc); $i++){
			if (!$this -> smtp -> Recipient($this -> bcc[$i][0])){
				$bad_rcpt[] = $this -> bcc[$i][0];
			}
		}

		if (count($bad_rcpt) > 0){ // Create error message
			for($i = 0; $i < count($bad_rcpt); $i++){
				if ($i != 0){
					$error .= ', ';
				}
				$error .= $bad_rcpt[$i];
			}
			$error = $this -> Lang('recipients_failed') . $error;
			$this -> SetError($error);
			$this -> smtp -> Reset();
			return false;
		}

		if (!$this -> smtp -> Data($header . $body)){
			$this -> SetError($this -> Lang('data_not_accepted'));
			$this -> smtp -> Reset();
			return false;
		}
		if ($this -> SMTPKeepAlive == true){
			$this -> smtp -> Reset();
		}else{
			$this -> SmtpClose();
		}

		return true;
	}

	/**
	 * Initiates a connection to an SMTP server.  Returns false if the
	 * operation failed.
	 * 
	 * @access private 
	 * @return bool 
	 */
	function SmtpConnect(){
		if ($this -> smtp == null){
			$this -> smtp = new SMTP();
		}

		$this -> smtp -> do_debug = $this -> SMTPDebug;
		$hosts = explode(';', $this -> Host);
		$index = 0;
		$connection = ($this -> smtp -> Connected());

		/**
		 * Retry while there is no connection
		 */
		while ($index < count($hosts) && $connection == false){
			$hostinfo = array();
			if (eregi('^(.+):([0-9]+)$', $hosts[$index], $hostinfo)){
				$host = $hostinfo[1];
				$port = $hostinfo[2];
			}else{
				$host = $hosts[$index];
				$port = $this -> Port;
			}

			if ($this -> smtp -> Connect(((!empty($this -> SMTPSecure))?$this -> SMTPSecure . '://':'') . $host, $port, $this -> Timeout)){
				if ($this -> Helo != ''){
					$this -> smtp -> Hello($this -> Helo);
				}else{
					$this -> smtp -> Hello($this -> ServerHostname());
				}

				$connection = true;
				if ($this -> SMTPAuth){
					if (!$this -> smtp -> Authenticate($this -> Username, $this -> Password)){
						$this -> SetError($this -> Lang('authenticate'));
						$this -> smtp -> Reset();
						$connection = false;
					}
				}
			}
			$index++;
		}
		if (!$connection){
			$this -> SetError($this -> Lang('connect_host'));
		}

		return $connection;
	}

	/**
	 * Closes the active SMTP session if one exists.
	 * 
	 * @return void 
	 */
	function SmtpClose(){
		if ($this -> smtp != null){
			if ($this -> smtp -> Connected()){
				$this -> smtp -> Quit();
				$this -> smtp -> Close();
			}
		}
	}

	/**
	 * Sets the language for all class error messages.  Returns false
	 * if it cannot load the language file.  The default language type
	 * is English.
	 * 
	 * @param string $lang_type Type of language (e.g. Portuguese: "br")
	 * @param string $lang_path Path to the language file directory
	 * @access public 
	 * @return bool 
	 */
	function SetLanguage($lang_type, $lang_path = 'language/'){
		if (file_exists($lang_path . 'phpmailer.lang-' . $lang_type . '.php')){
			include($lang_path . 'phpmailer.lang-' . $lang_type . '.php');
		}elseif (file_exists($lang_path . 'phpmailer.lang-en.php')){
			include($lang_path . 'phpmailer.lang-en.php');
		}else{
			$PHPMAILER_LANG = array();
			$PHPMAILER_LANG["provide_address"] = 'You must provide at least one ' . $PHPMAILER_LANG["mailer_not_supported"] = ' mailer is not supported.';
			$PHPMAILER_LANG["execute"] = 'Could not execute: ';
			$PHPMAILER_LANG["instantiate"] = 'Could not instantiate mail function.';
			$PHPMAILER_LANG["authenticate"] = 'SMTP Error: Could not authenticate.';
			$PHPMAILER_LANG["from_failed"] = 'The following From address failed: ';
			$PHPMAILER_LANG["recipients_failed"] = 'SMTP Error: The following ' . $PHPMAILER_LANG["data_not_accepted"] = 'SMTP Error: Data not accepted.';
			$PHPMAILER_LANG["connect_host"] = 'SMTP Error: Could not connect to SMTP host.';
			$PHPMAILER_LANG["file_access"] = 'Could not access file: ';
			$PHPMAILER_LANG["file_open"] = 'File Error: Could not open file: ';
			$PHPMAILER_LANG["encoding"] = 'Unknown encoding: ';
			$PHPMAILER_LANG["signing"] = 'Signing Error: ';
		}
		$this -> language = $PHPMAILER_LANG;

		return true;
	} 
	// ///////////////////////////////////////////////
	// METHODS, MESSAGE CREATION
	// ///////////////////////////////////////////////
	/**
	 * Creates recipient headers.
	 * 
	 * @access private 
	 * @return string 
	 */
	function AddrAppend($type, $addr){
		$addr_str = $type . ': ';
		$addr_str .= $this -> AddrFormat($addr[0]);
		if (count($addr) > 1){
			for($i = 1; $i < count($addr); $i++){
				$addr_str .= ', ' . $this -> AddrFormat($addr[$i]);
			}
		}
		$addr_str .= $this -> LE;

		return $addr_str;
	}

	/**
	 * Formats an address correctly.
	 * 
	 * @access private 
	 * @return string 
	 */
	function AddrFormat($addr){
		if (empty($addr[1])){
			$formatted = $this -> SecureHeader($addr[0]);
		}else{
			$formatted = $this -> EncodeHeader($this -> SecureHeader($addr[1]), 'phrase') . " <" . $this -> SecureHeader($addr[0]) . ">";
		}

		return $formatted;
	}

	/**
	 * Wraps message for use with mailers that do not
	 * automatically perform wrapping and for quoted-printable.
	 * Original written by philippe.
	 * 
	 * @access private 
	 * @return string 
	 */
	function WrapText($message, $length, $qp_mode = false){
		$soft_break = ($qp_mode) ? sprintf(" =%s", $this -> LE) : $this -> LE; 
		// If utf-8 encoding is used, we will need to make sure we don't
		// split multibyte characters when we wrap
		$is_utf8 = (strtolower($this -> CharSet) == "utf-8");

		$message = $this -> FixEOL($message);
		if (substr($message, -1) == $this -> LE){
			$message = substr($message, 0, -1);
		}

		$line = explode($this -> LE, $message);
		$message = '';
		for ($i = 0 ;$i < count($line); $i++){
			$line_part = explode(' ', $line[$i]);
			$buf = '';
			for ($e = 0; $e < count($line_part); $e++){
				$word = $line_part[$e];
				if ($qp_mode and (strlen($word) > $length)){
					$space_left = $length - strlen($buf) - 1;
					if ($e != 0){
						if ($space_left > 20){
							$len = $space_left;
							if ($is_utf8){
								$len = $this -> UTF8CharBoundary($word, $len);
							}elseif (substr($word, $len - 1, 1) == "="){
								$len--;
							}elseif (substr($word, $len - 2, 1) == "="){
								$len -= 2;
							}
							$part = substr($word, 0, $len);
							$word = substr($word, $len);
							$buf .= ' ' . $part;
							$message .= $buf . sprintf("=%s", $this -> LE);
						}else{
							$message .= $buf . $soft_break;
						}
						$buf = '';
					} while (strlen($word) > 0){
						$len = $length;
						if ($is_utf8){
							$len = $this -> UTF8CharBoundary($word, $len);
						}elseif (substr($word, $len - 1, 1) == "="){
							$len--;
						}elseif (substr($word, $len - 2, 1) == "="){
							$len -= 2;
						}
						$part = substr($word, 0, $len);
						$word = substr($word, $len);

						if (strlen($word) > 0){
							$message .= $part . sprintf("=%s", $this -> LE);
						}else{
							$buf = $part;
						}
					}
				}else{
					$buf_o = $buf;
					$buf .= ($e == 0) ? $word : (' ' . $word);

					if (strlen($buf) > $length and $buf_o != ''){
						$message .= $buf_o . $soft_break;
						$buf = $word;
					}
				}
			}
			$message .= $buf . $this -> LE;
		}

		return $message;
	}

	/**
	 * Finds last character boundary prior to maxLength in a utf-8
	 * quoted (printable) encoded string.
	 * Original written by Colin Brown.
	 * 
	 * @access private 
	 * @param string $encodedText utf-8 QP text
	 * @param int $maxLength find last character boundary prior to this length
	 * @return int 
	 */
	function UTF8CharBoundary($encodedText, $maxLength){
		$foundSplitPos = false;
		$lookBack = 3;
		while (!$foundSplitPos){
			$lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
			$encodedCharPos = strpos($lastChunk, "=");
			if ($encodedCharPos !== false){ 
				// Found start of encoded character byte within $lookBack block.
				// Check the encoded byte value (the 2 chars after the '=')
				$hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
				$dec = hexdec($hex);
				if ($dec < 128){ // Single byte character. 
					// If the encoded char was found at pos 0, it will fit
					// otherwise reduce maxLength to start of the encoded char
					$maxLength = ($encodedCharPos == 0) ? $maxLength :
					$maxLength - ($lookBack - $encodedCharPos);
					$foundSplitPos = true;
				}elseif ($dec >= 192){ // First byte of a multi byte character 
					// Reduce maxLength to split at start of character
					$maxLength = $maxLength - ($lookBack - $encodedCharPos);
					$foundSplitPos = true;
				}elseif ($dec < 192){ // Middle byte of a multi byte character, look further back
					$lookBack += 3;
				}
			}else{ 
				// No encoded character found
				$foundSplitPos = true;
			}
		}
		return $maxLength;
	}

	/**
	 * Set the body wrapping.
	 * 
	 * @access private 
	 * @return void 
	 */
	function SetWordWrap(){
		if ($this -> WordWrap < 1){
			return;
		}

		switch ($this -> message_type){
			case 'alt':
			/**
			 * fall through
			 */
			case 'alt_attachments':
				$this -> AltBody = $this -> WrapText($this -> AltBody, $this -> WordWrap);
				break;
			default:
				$this -> Body = $this -> WrapText($this -> Body, $this -> WordWrap);
				break;
		}
	}

	/**
	 * Assembles message header.
	 * 
	 * @access private 
	 * @return string 
	 */
	function CreateHeader(){
		$result = '';

		/**
		 * Set the boundaries
		 */
		$uniq_id = md5(uniqid(time()));
		$this -> boundary[1] = 'b1_' . $uniq_id;
		$this -> boundary[2] = 'b2_' . $uniq_id;

		$result .= $this -> HeaderLine('Date', $this -> RFCDate());
		if ($this -> Sender == ''){
			$result .= $this -> HeaderLine('Return-Path', trim($this -> From));
		}else{
			$result .= $this -> HeaderLine('Return-Path', trim($this -> Sender));
		}

		/**
		 * To be created automatically by mail()
		 */
		if ($this -> Mailer != 'mail'){
			if (count($this -> to) > 0){
				$result .= $this -> AddrAppend('To', $this -> to);
			}elseif (count($this -> cc) == 0){
				$result .= $this -> HeaderLine('To', 'undisclosed-recipients:;');
			}
		}

		$from = array();
		$from[0][0] = trim($this -> From);
		$from[0][1] = $this -> FromName;
		$result .= $this -> AddrAppend('From', $from);

		/**
		 * sendmail and mail() extract Cc from the header before sending
		 */
		if ((($this -> Mailer == 'sendmail') || ($this -> Mailer == 'mail')) && (count($this -> cc) > 0)){
			$result .= $this -> AddrAppend('Cc', $this -> cc);
		}

		/**
		 * sendmail and mail() extract Bcc from the header before sending
		 */
		if ((($this -> Mailer == 'sendmail') || ($this -> Mailer == 'mail')) && (count($this -> bcc) > 0)){
			$result .= $this -> AddrAppend('Bcc', $this -> bcc);
		}

		if (count($this -> ReplyTo) > 0){
			$result .= $this -> AddrAppend('Reply-To', $this -> ReplyTo);
		}

		/**
		 * mail() sets the subject itself
		 */
		if ($this -> Mailer != 'mail'){
			$result .= $this -> HeaderLine('Subject', $this -> EncodeHeader($this -> SecureHeader($this -> Subject)));
		}

		if ($this -> MessageID != ''){
			$result .= $this -> HeaderLine('Message-ID', $this -> MessageID);
		}else{
			$result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this -> ServerHostname(), $this -> LE);
		}
		$result .= $this -> HeaderLine('X-Priority', $this -> Priority); 
		// $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']');
		if ($this -> ConfirmReadingTo != ''){
			$result .= $this -> HeaderLine('Disposition-Notification-To', '<' . trim($this -> ConfirmReadingTo) . '>');
		} 
		// Add custom headers
		for($index = 0; $index < count($this -> CustomHeader); $index++){
			$result .= $this -> HeaderLine(trim($this -> CustomHeader[$index][0]), $this -> EncodeHeader(trim($this -> CustomHeader[$index][1])));
		}
		if (!$this -> sign_key_file){
			$result .= $this -> HeaderLine('MIME-Version', '1.0');
			$result .= $this -> GetMailMIME();
		}

		return $result;
	}

	/**
	 * Returns the message MIME.
	 * 
	 * @access private 
	 * @return string 
	 */
	function GetMailMIME(){
		$result = '';
		switch ($this -> message_type){
			case 'plain':
				$result .= $this -> HeaderLine('Content-Transfer-Encoding', $this -> Encoding);
				$result .= sprintf("Content-Type: %s; charset=\"%s\"", $this -> ContentType, $this -> CharSet);
				break;
			case 'attachments':
			/**
			 * fall through
			 */
			case 'alt_attachments':
				if ($this -> InlineImageExists()){
					$result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this -> LE, $this -> LE, $this -> boundary[1], $this -> LE);
				}else{
					$result .= $this -> HeaderLine('Content-Type', 'multipart/mixed;');
					$result .= $this -> TextLine("\tboundary=\"" . $this -> boundary[1] . '"');
				}
				break;
			case 'alt':
				$result .= $this -> HeaderLine('Content-Type', 'multipart/alternative;');
				$result .= $this -> TextLine("\tboundary=\"" . $this -> boundary[1] . '"');
				break;
		}

		if ($this -> Mailer != 'mail'){
			$result .= $this -> LE . $this -> LE;
		}

		return $result;
	}

	/**
	 * Assembles the message body.  Returns an empty string on failure.
	 * 
	 * @access private 
	 * @return string 
	 */
	function CreateBody(){
		$result = '';
		if ($this -> sign_key_file){
			$result .= $this -> GetMailMIME();
		}

		$this -> SetWordWrap();

		switch ($this -> message_type){
			case 'alt':
				$result .= $this -> GetBoundary($this -> boundary[1], '', 'text/plain', '');
				$result .= $this -> EncodeString($this -> AltBody, $this -> Encoding);
				$result .= $this -> LE . $this -> LE;
				$result .= $this -> GetBoundary($this -> boundary[1], '', 'text/html', '');
				$result .= $this -> EncodeString($this -> Body, $this -> Encoding);
				$result .= $this -> LE . $this -> LE;
				$result .= $this -> EndBoundary($this -> boundary[1]);
				break;
			case 'plain':
				$result .= $this -> EncodeString($this -> Body, $this -> Encoding);
				break;
			case 'attachments':
				$result .= $this -> GetBoundary($this -> boundary[1], '', '', '');
				$result .= $this -> EncodeString($this -> Body, $this -> Encoding);
				$result .= $this -> LE;
				$result .= $this -> AttachAll();
				break;
			case 'alt_attachments':
				$result .= sprintf("--%s%s", $this -> boundary[1], $this -> LE);
				$result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this -> LE, $this -> boundary[2], $this -> LE . $this -> LE);
				$result .= $this -> GetBoundary($this -> boundary[2], '', 'text/plain', '') . $this -> LE; // Create text body
				$result .= $this -> EncodeString($this -> AltBody, $this -> Encoding);
				$result .= $this -> LE . $this -> LE;
				$result .= $this -> GetBoundary($this -> boundary[2], '', 'text/html', '') . $this -> LE; // Create the HTML body
				$result .= $this -> EncodeString($this -> Body, $this -> Encoding);
				$result .= $this -> LE . $this -> LE;
				$result .= $this -> EndBoundary($this -> boundary[2]);
				$result .= $this -> AttachAll();
				break;
		}

		if ($this -> IsError()){
			$result = '';
		}else if ($this -> sign_key_file){
			$file = tempnam("", "mail");
			$fp = fopen($file, "w");
			fwrite($fp, $result);
			fclose($fp);
			$signed = tempnam("", "signed");

			if (@openssl_pkcs7_sign($file, $signed, "file://" . $this -> sign_cert_file, array("file://" . $this -> sign_key_file, $this -> sign_key_pass), null)){
				$fp = fopen($signed, "r");
				$result = fread($fp, filesize($this -> sign_key_file));
				$result = '';
				while (!feof($fp)){
					$result = $result . fread($fp, 1024);
				}
				fclose($fp);
			}else{
				$this -> SetError($this -> Lang("signing") . openssl_error_string());
				$result = '';
			}

			unlink($file);
			unlink($signed);
		}

		return $result;
	}

	/**
	 * Returns the start of a message boundary.
	 * 
	 * @access private 
	 */
	function GetBoundary($boundary, $charSet, $contentType, $encoding){
		$result = '';
		if ($charSet == ''){
			$charSet = $this -> CharSet;
		}
		if ($contentType == ''){
			$contentType = $this -> ContentType;
		}
		if ($encoding == ''){
			$encoding = $this -> Encoding;
		}
		$result .= $this -> TextLine('--' . $boundary);
		$result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
		$result .= $this -> LE;
		$result .= $this -> HeaderLine('Content-Transfer-Encoding', $encoding);
		$result .= $this -> LE;

		return $result;
	}

	/**
	 * Returns the end of a message boundary.
	 * 
	 * @access private 
	 */
	function EndBoundary($boundary){
		return $this -> LE . '--' . $boundary . '--' . $this -> LE;
	}

	/**
	 * Sets the message type.
	 * 
	 * @access private 
	 * @return void 
	 */
	function SetMessageType(){
		if (count($this -> attachment) < 1 && strlen($this -> AltBody) < 1){
			$this -> message_type = 'plain';
		}else{
			if (count($this -> attachment) > 0){
				$this -> message_type = 'attachments';
			}
			if (strlen($this -> AltBody) > 0 && count($this -> attachment) < 1){
				$this -> message_type = 'alt';
			}
			if (strlen($this -> AltBody) > 0 && count($this -> attachment) > 0){
				$this -> message_type = 'alt_attachments';
			}
		}
	}

	/**
	 * Returns a formatted header line.
	 * 
	 * @access private 
	 * @return string 
	 */
	function HeaderLine($name, $value){
		return $name . ': ' . $value . $this -> LE;
	}

	/**
	 * Returns a formatted mail line.
	 * 
	 * @access private 
	 * @return string 
	 */
	function TextLine($value){
		return $value . $this -> LE;
	} 
	// ///////////////////////////////////////////////
	// CLASS METHODS, ATTACHMENTS
	// ///////////////////////////////////////////////
	/**
	 * Adds an attachment from a path on the filesystem.
	 * Returns false if the file could not be found
	 * or accessed.
	 * 
	 * @param string $path Path to the attachment.
	 * @param string $name Overrides the attachment name.
	 * @param string $encoding File encoding (see $Encoding).
	 * @param string $type File extension (MIME) type.
	 * @return bool 
	 */
	function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream'){
		if (!@is_file($path)){
			$this -> SetError($this -> Lang('file_access') . $path);
			return false;
		}

		$filename = basename($path);
		if ($name == ''){
			$name = $filename;
		}

		$cur = count($this -> attachment);
		$this -> attachment[$cur][0] = $path;
		$this -> attachment[$cur][1] = $filename;
		$this -> attachment[$cur][2] = $name;
		$this -> attachment[$cur][3] = $encoding;
		$this -> attachment[$cur][4] = $type;
		$this -> attachment[$cur][5] = false; // isStringAttachment
		$this -> attachment[$cur][6] = 'attachment';
		$this -> attachment[$cur][7] = 0;

		return true;
	}

	/**
	 * Attaches all fs, string, and binary attachments to the message.
	 * Returns an empty string on failure.
	 * 
	 * @access private 
	 * @return string 
	 */
	function AttachAll(){
		/**
		 * Return text of body
		 */
		$mime = array();

		/**
		 * Add all attachments
		 */
		for($i = 0; $i < count($this -> attachment); $i++){
			/**
			 * Check for string attachment
			 */
			$bString = $this -> attachment[$i][5];
			if ($bString){
				$string = $this -> attachment[$i][0];
			}else{
				$path = $this -> attachment[$i][0];
			}

			$filename = $this -> attachment[$i][1];
			$name = $this -> attachment[$i][2];
			$encoding = $this -> attachment[$i][3];
			$type = $this -> attachment[$i][4];
			$disposition = $this -> attachment[$i][6];
			$cid = $this -> attachment[$i][7];

			$mime[] = sprintf("--%s%s", $this -> boundary[1], $this -> LE);
			$mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this -> EncodeHeader($this -> SecureHeader($name)), $this -> LE);
			$mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this -> LE);

			if ($disposition == 'inline'){
				$mime[] = sprintf("Content-ID: <%s>%s", $cid, $this -> LE);
			}

			$mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this -> EncodeHeader($this -> SecureHeader($name)), $this -> LE . $this -> LE);

			/**
			 * Encode as string attachment
			 */
			if ($bString){
				$mime[] = $this -> EncodeString($string, $encoding);
				if ($this -> IsError()){
					return '';
				}
				$mime[] = $this -> LE . $this -> LE;
			}else{
				$mime[] = $this -> EncodeFile($path, $encoding);
				if ($this -> IsError()){
					return '';
				}
				$mime[] = $this -> LE . $this -> LE;
			}
		}

		$mime[] = sprintf("--%s--%s", $this -> boundary[1], $this -> LE);

		return join('', $mime);
	}

	/**
	 * Encodes attachment in requested format.  Returns an
	 * empty string on failure.
	 * 
	 * @access private 
	 * @return string 
	 */
	function EncodeFile ($path, $encoding = 'base64'){
		if (!@$fd = fopen($path, 'rb')){
			$this -> SetError($this -> Lang('file_open') . $path);
			return '';
		}
		$magic_quotes = get_magic_quotes_runtime();
		set_magic_quotes_runtime(0);
		$file_buffer = fread($fd, filesize($path));
		$file_buffer = $this -> EncodeString($file_buffer, $encoding);
		fclose($fd);
		set_magic_quotes_runtime($magic_quotes);

		return $file_buffer;
	}

	/**
	 * Encodes string to requested format. Returns an
	 * empty string on failure.
	 * 
	 * @access private 
	 * @return string 
	 */
	function EncodeString ($str, $encoding = 'base64'){
		$encoded = '';
		switch (strtolower($encoding)){
			case 'base64':
				/**
				 * chunk_split is found in PHP >= 3.0.6
				 */
				$encoded = chunk_split(base64_encode($str), 76, $this -> LE);
				break;
			case '7bit':
			case '8bit':
				$encoded = $this -> FixEOL($str);
				if (substr($encoded, - (strlen($this -> LE))) != $this -> LE)
					$encoded .= $this -> LE;
				break;
			case 'binary':
				$encoded = $str;
				break;
			case 'quoted-printable':
				$encoded = $this -> EncodeQP($str);
				break;
			default:
				$this -> SetError($this -> Lang('encoding') . $encoding);
				break;
		}
		return $encoded;
	}

	/**
	 * Encode a header string to best of Q, B, quoted or none.
	 * 
	 * @access private 
	 * @return string 
	 */
	function EncodeHeader ($str, $position = 'text'){
		$x = 0;

		switch (strtolower($position)){
			case 'phrase':
				if (!preg_match('/[\200-\377]/', $str)){
					/**
					 * Can't use addslashes as we don't know what value has magic_quotes_sybase.
					 */
					$encoded = addcslashes($str, "\0..\37\177\\\"");
					if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)){
						return ($encoded);
					}else{
						return ("\"$encoded\"");
					}
				}
				$x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
				break;
			case 'comment':
				$x = preg_match_all('/[()"]/', $str, $matches);
				/**
				 * Fall-through
				 */
			case 'text':
			default:
				$x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
				break;
		}

		if ($x == 0){
			return ($str);
		}

		$maxlen = 75 - 7 - strlen($this -> CharSet);
		/**
		 * Try to select the encoding which should produce the shortest output
		 */
		if (strlen($str) / 3 < $x){
			$encoding = 'B';
			if (function_exists('mb_strlen') && $this -> HasMultiBytes($str)){ 
				// Use a custom function which correctly encodes and wraps long
				// multibyte strings without breaking lines within a character
				$encoded = $this -> Base64EncodeWrapMB($str);
			}else{
				$encoded = base64_encode($str);
				$maxlen -= $maxlen % 4;
				$encoded = trim(chunk_split($encoded, $maxlen, "\n"));
			}
		}else{
			$encoding = 'Q';
			$encoded = $this -> EncodeQ($str, $position);
			$encoded = $this -> WrapText($encoded, $maxlen, true);
			$encoded = str_replace('=' . $this -> LE, "\n", trim($encoded));
		}

		$encoded = preg_replace('/^(.*)$/m', " =?" . $this -> CharSet . "?$encoding?\\1?=", $encoded);
		$encoded = trim(str_replace("\n", $this -> LE, $encoded));

		return $encoded;
	}

	/**
	 * Checks if a string contains multibyte characters.
	 * 
	 * @access private 
	 * @param string $str multi-byte text to wrap encode
	 * @return bool 
	 */
	function HasMultiBytes($str){
		if (function_exists('mb_strlen')){
			return (strlen($str) > mb_strlen($str, $this -> CharSet));
		}else{ // Assume no multibytes (we can't handle without mbstring functions anyway)
			return false;
		}
	}

	/**
	 * Correctly encodes and wraps long multibyte strings for mail headers
	 * without breaking lines within a character.
	 * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
	 * 
	 * @access private 
	 * @param string $str multi-byte text to wrap encode
	 * @return string 
	 */
	function Base64EncodeWrapMB($str){
		$start = "=?" . $this -> CharSet . "?B?";
		$end = "?=";
		$encoded = "";

		$mb_length = mb_strlen($str, $this -> CharSet); 
		// Each line must have length <= 75, including $start and $end
		$length = 75 - strlen($start) - strlen($end); 
		// Average multi-byte ratio
		$ratio = $mb_length / strlen($str); 
		// Base64 has a 4:3 ratio
		$offset = $avgLength = floor($length * $ratio * .75);

		for ($i = 0; $i < $mb_length; $i += $offset){
			$lookBack = 0;

			do{
				$offset = $avgLength - $lookBack;
				$chunk = mb_substr($str, $i, $offset, $this -> CharSet);
				$chunk = base64_encode($chunk);
				$lookBack++;
			} while (strlen($chunk) > $length);

			$encoded .= $chunk . $this -> LE;
		} 
		// Chomp the last linefeed
		$encoded = substr($encoded, 0, - strlen($this -> LE));
		return $encoded;
	}

	/**
	 * Encode string to quoted-printable.
	 * 
	 * @access private 
	 * @return string 
	 */
	function EncodeQP($input = '', $line_max = 76, $space_conv = false){
		$hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
		$lines = preg_split('/(?:\r\n|\r|\n)/', $input);
		$eol = "\r\n";
		$escape = '=';
		$output = '';
		while (list(, $line) = each($lines)){
			$linlen = strlen($line);
			$newline = '';
			for($i = 0; $i < $linlen; $i++){
				$c = substr($line, $i, 1);
				$dec = ord($c);
				if (($i == 0) && ($dec == 46)){ // convert first point in the line into =2E
					$c = '=2E';
				}
				if ($dec == 32){
					if ($i == ($linlen - 1)){ // convert space at eol only
						$c = '=20';
					}else if ($space_conv){
						$c = '=20';
					}
				}elseif (($dec == 61) || ($dec < 32) || ($dec > 126)){ // always encode "\t", which is *not* required
					$h2 = floor($dec / 16);
					$h1 = floor($dec % 16);
					$c = $escape . $hex[$h2] . $hex[$h1];
				}
				if ((strlen($newline) + strlen($c)) >= $line_max){ // CRLF is not counted
					$output .= $newline . $escape . $eol; //  soft line break; " =\r\n" is okay
					$newline = ''; 
					// check if newline first character will be point or not
					if ($dec == 46){
						$c = '=2E';
					}
				}
				$newline .= $c;
			} // end of for
			$output .= $newline . $eol;
		} // end of while
		return $output;
	}

	/**
	 * Encode string to q encoding.
	 * 
	 * @access private 
	 * @return string 
	 */
	function EncodeQ ($str, $position = 'text'){
		/**
		 * There should not be any EOL in the string
		 */
		$encoded = preg_replace("[\r\n]", '', $str);

		switch (strtolower($position)){
			case 'phrase':
				$encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
				break;
			case 'comment':
				$encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
			case 'text':
			default:
				/**
				 * Replace every high ascii, control =, ? and _ characters
				 */
				$encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
					"'='.sprintf('%02X', ord('\\1'))", $encoded);
				break;
		}

		/**
		 * Replace every spaces to _ (more readable than =20)
		 */
		$encoded = str_replace(' ', '_', $encoded);

		return $encoded;
	}

	/**
	 * Adds a string or binary attachment (non-filesystem) to the list.
	 * This method can be used to attach ascii or binary data,
	 * such as a BLOB record from a database.
	 * 
	 * @param string $string String attachment data.
	 * @param string $filename Name of the attachment.
	 * @param string $encoding File encoding (see $Encoding).
	 * @param string $type File extension (MIME) type.
	 * @return void 
	 */
	function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream'){
		/**
		 * Append to $attachment array
		 */
		$cur = count($this -> attachment);
		$this -> attachment[$cur][0] = $string;
		$this -> attachment[$cur][1] = $filename;
		$this -> attachment[$cur][2] = $filename;
		$this -> attachment[$cur][3] = $encoding;
		$this -> attachment[$cur][4] = $type;
		$this -> attachment[$cur][5] = true; // isString
		$this -> attachment[$cur][6] = 'attachment';
		$this -> attachment[$cur][7] = 0;
	}

	/**
	 * Adds an embedded attachment.  This can include images, sounds, and
	 * just about any other document.  Make sure to set the $type to an
	 * image type.  For JPEG images use "image/jpeg" and for GIF images
	 * use "image/gif".
	 * 
	 * @param string $path Path to the attachment.
	 * @param string $cid Content ID of the attachment.  Use this to identify the Id for accessing the image in an HTML form.
	 * @param string $name Overrides the attachment name.
	 * @param string $encoding File encoding (see $Encoding).
	 * @param string $type File extension (MIME) type.
	 * @return bool 
	 */
	function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream'){
		if (!@is_file($path)){
			$this -> SetError($this -> Lang('file_access') . $path);
			return false;
		}

		$filename = basename($path);
		if ($name == ''){
			$name = $filename;
		}

		/**
		 * Append to $attachment array
		 */
		$cur = count($this -> attachment);
		$this -> attachment[$cur][0] = $path;
		$this -> attachment[$cur][1] = $filename;
		$this -> attachment[$cur][2] = $name;
		$this -> attachment[$cur][3] = $encoding;
		$this -> attachment[$cur][4] = $type;
		$this -> attachment[$cur][5] = false;
		$this -> attachment[$cur][6] = 'inline';
		$this -> attachment[$cur][7] = $cid;

		return true;
	}

	/**
	 * Returns true if an inline attachment is present.
	 * 
	 * @access private 
	 * @return bool 
	 */
	function InlineImageExists(){
		$result = false;
		for($i = 0; $i < count($this -> attachment); $i++){
			if ($this -> attachment[$i][6] == 'inline'){
				$result = true;
				break;
			}
		}

		return $result;
	} 
	// ///////////////////////////////////////////////
	// CLASS METHODS, MESSAGE RESET
	// ///////////////////////////////////////////////
	/**
	 * Clears all recipients assigned in the TO array.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearAddresses(){
		$this -> to = array();
	}

	/**
	 * Clears all recipients assigned in the CC array.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearCCs(){
		$this -> cc = array();
	}

	/**
	 * Clears all recipients assigned in the BCC array.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearBCCs(){
		$this -> bcc = array();
	}

	/**
	 * Clears all recipients assigned in the ReplyTo array.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearReplyTos(){
		$this -> ReplyTo = array();
	}

	/**
	 * Clears all recipients assigned in the TO, CC and BCC
	 * array.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearAllRecipients(){
		$this -> to = array();
		$this -> cc = array();
		$this -> bcc = array();
	}

	/**
	 * Clears all previously set filesystem, string, and binary
	 * attachments.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearAttachments(){
		$this -> attachment = array();
	}

	/**
	 * Clears all custom headers.  Returns void.
	 * 
	 * @return void 
	 */
	function ClearCustomHeaders(){
		$this -> CustomHeader = array();
	} 
	// ///////////////////////////////////////////////
	// CLASS METHODS, MISCELLANEOUS
	// ///////////////////////////////////////////////
	/**
	 * Adds the error message to the error container.
	 * Returns void.
	 * 
	 * @access private 
	 * @return void 
	 */
	function SetError($msg){
		$this -> error_count++;
		$this -> ErrorInfo = $msg;
	}

	/**
	 * Returns the proper RFC 822 formatted date.
	 * 
	 * @access private 
	 * @return string 
	 */
	function RFCDate(){
		$tz = date('Z');
		$tzs = ($tz < 0) ? '-' : '+';
		$tz = abs($tz);
		$tz = (int)($tz / 3600) * 100 + ($tz % 3600) / 60;
		$result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);

		return $result;
	}

	/**
	 * Returns the appropriate server variable.  Should work with both
	 * PHP 4.1.0+ as well as older versions.  Returns an empty string
	 * if nothing is found.
	 * 
	 * @access private 
	 * @return mixed 
	 */
	function ServerVar($varName){
		global $HTTP_SERVER_VARS;
		global $HTTP_ENV_VARS;

		if (!isset($_SERVER)){
			$_SERVER = $HTTP_SERVER_VARS;
			if (!isset($_SERVER['REMOTE_ADDR'])){
				$_SERVER = $HTTP_ENV_VARS; // must be Apache
			}
		}

		if (isset($_SERVER[$varName])){
			return $_SERVER[$varName];
		}else{
			return '';
		}
	}

	/**
	 * Returns the server hostname or 'localhost.localdomain' if unknown.
	 * 
	 * @access private 
	 * @return string 
	 */
	function ServerHostname(){
		if ($this -> Hostname != ''){
			$result = $this -> Hostname;
		}elseif ($this -> ServerVar('SERVER_NAME') != ''){
			$result = $this -> ServerVar('SERVER_NAME');
		}else{
			$result = 'localhost.localdomain';
		}

		return $result;
	}

	/**
	 * Returns a message in the appropriate language.
	 * 
	 * @access private 
	 * @return string 
	 */
	function Lang($key){
		if (count($this -> language) < 1){
			$this -> SetLanguage('en'); // set the default language
		}

		if (isset($this -> language[$key])){
			return $this -> language[$key];
		}else{
			return 'Language string failed to load: ' . $key;
		}
	}

	/**
	 * Returns true if an error occurred.
	 * 
	 * @return bool 
	 */
	function IsError(){
		return ($this -> error_count > 0);
	}

	/**
	 * Changes every end of line from CR or LF to CRLF.
	 * 
	 * @access private 
	 * @return string 
	 */
	function FixEOL($str){
		$str = str_replace("\r\n", "\n", $str);
		$str = str_replace("\r", "\n", $str);
		$str = str_replace("\n", $this -> LE, $str);
		return $str;
	}

	/**
	 * Adds a custom header.
	 * 
	 * @return void 
	 */
	function AddCustomHeader($custom_header){
		$this -> CustomHeader[] = explode(':', $custom_header, 2);
	}

	/**
	 * Evaluates the message and returns modifications for inline images and backgrounds
	 * 
	 * @access public 
	 * @return $message
	 */
	function MsgHTML($message, $basedir = ''){
		preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
		if (isset($images[2])){
			foreach($images[2] as $i => $url){ 
				// do not change urls for absolute images (thanks to corvuscorax)
				if (!preg_match('/^[A-z][A-z]*:\/\//', $url)){
					$filename = basename($url);
					$directory = dirname($url);
					($directory == '.')?$directory = '':'';
					$cid = 'cid:' . md5($filename);
					$fileParts = split("\.", $filename);
					$ext = $fileParts[1];
					$mimeType = $this -> _mime_types($ext);
					if (strlen($basedir) > 1 && substr($basedir, -1) != '/'){
						$basedir .= '/';
					}
					if (strlen($directory) > 1 && substr($directory, -1) != '/'){
						$directory .= '/';
					}
					if ($this -> AddEmbeddedImage($basedir . $directory . $filename, md5($filename), $filename, 'base64', $mimeType)){
						$message = preg_replace("/" . $images[1][$i] . "=\"" . preg_quote($url, '/') . "\"/Ui", $images[1][$i] . "=\"" . $cid . "\"", $message);
					}
				}
			}
		}
		$this -> IsHTML(true);
		$this -> Body = $message;
		$textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $message)));
		if (!empty($textMsg) && empty($this -> AltBody)){
			$this -> AltBody = html_entity_decode($textMsg);
		}
		if (empty($this -> AltBody)){
			$this -> AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n";
		}
	}

	/**
	 * Gets the mime type of the embedded or inline image
	 * 
	 * @access private 
	 * @return mime type of ext
	 */
	function _mime_types($ext = ''){
		$mimes = array('ai' => 'application/postscript',
			'aif' => 'audio/x-aiff',
			'aifc' => 'audio/x-aiff',
			'aiff' => 'audio/x-aiff',
			'avi' => 'video/x-msvideo',
			'bin' => 'application/macbinary',
			'bmp' => 'image/bmp',
			'class' => 'application/octet-stream',
			'cpt' => 'application/mac-compactpro',
			'css' => 'text/css',
			'dcr' => 'application/x-director',
			'dir' => 'application/x-director',
			'dll' => 'application/octet-stream',
			'dms' => 'application/octet-stream',
			'doc' => 'application/msword',
			'dvi' => 'application/x-dvi',
			'dxr' => 'application/x-director',
			'eml' => 'message/rfc822',
			'eps' => 'application/postscript',
			'exe' => 'application/octet-stream',
			'gif' => 'image/gif',
			'gtar' => 'application/x-gtar',
			'htm' => 'text/html',
			'html' => 'text/html',
			'jpe' => 'image/jpeg',
			'jpeg' => 'image/jpeg',
			'jpg' => 'image/jpeg',
			'hqx' => 'application/mac-binhex40',
			'js' => 'application/x-javascript',
			'lha' => 'application/octet-stream',
			'log' => 'text/plain',
			'lzh' => 'application/octet-stream',
			'mid' => 'audio/midi',
			'midi' => 'audio/midi',
			'mif' => 'application/vnd.mif',
			'mov' => 'video/quicktime',
			'movie' => 'video/x-sgi-movie',
			'mp2' => 'audio/mpeg',
			'mp3' => 'audio/mpeg',
			'mpe' => 'video/mpeg',
			'mpeg' => 'video/mpeg',
			'mpg' => 'video/mpeg',
			'mpga' => 'audio/mpeg',
			'oda' => 'application/oda',
			'pdf' => 'application/pdf',
			'php' => 'application/x-httpd-php',
			'php3' => 'application/x-httpd-php',
			'php4' => 'application/x-httpd-php',
			'phps' => 'application/x-httpd-php-source',
			'phtml' => 'application/x-httpd-php',
			'png' => 'image/png',
			'ppt' => 'application/vnd.ms-powerpoint',
			'ps' => 'application/postscript',
			'psd' => 'application/octet-stream',
			'qt' => 'video/quicktime',
			'ra' => 'audio/x-realaudio',
			'ram' => 'audio/x-pn-realaudio',
			'rm' => 'audio/x-pn-realaudio',
			'rpm' => 'audio/x-pn-realaudio-plugin',
			'rtf' => 'text/rtf',
			'rtx' => 'text/richtext',
			'rv' => 'video/vnd.rn-realvideo',
			'sea' => 'application/octet-stream',
			'shtml' => 'text/html',
			'sit' => 'application/x-stuffit',
			'so' => 'application/octet-stream',
			'smi' => 'application/smil',
			'smil' => 'application/smil',
			'swf' => 'application/x-shockwave-flash',
			'tar' => 'application/x-tar',
			'text' => 'text/plain',
			'txt' => 'text/plain',
			'tgz' => 'application/x-tar',
			'tif' => 'image/tiff',
			'tiff' => 'image/tiff',
			'wav' => 'audio/x-wav',
			'wbxml' => 'application/vnd.wap.wbxml',
			'wmlc' => 'application/vnd.wap.wmlc',
			'word' => 'application/msword',
			'xht' => 'application/xhtml+xml',
			'xhtml' => 'application/xhtml+xml',
			'xl' => 'application/excel',
			'xls' => 'application/vnd.ms-excel',
			'xml' => 'text/xml',
			'xsl' => 'text/xml',
			'zip' => 'application/zip'
			);
		return (! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
	}

	/**
	 * Set (or reset) Class Objects (variables)
	 * 
	 * Usage Example:
	 * $page->set('X-Priority', '3');
	 * 
	 * @access public 
	 * @param string $name Parameter Name
	 * @param mixed $value Parameter Value
	 * NOTE: will not work with arrays, there are no arrays to set/reset
	 */
	function set ($name, $value = ''){
		if (isset($this -> $name)){
			$this -> $name = $value;
		}else{
			$this -> SetError('Cannot set or reset variable ' . $name);
			return false;
		}
	}

	/**
	 * Read a file from a supplied filename and return it.
	 * 
	 * @access public 
	 * @param string $filename Parameter File Name
	 */
	function getFile($filename){
		$return = '';
		if ($fp = fopen($filename, 'rb')){
			while (!feof($fp)){
				$return .= fread($fp, 1024);
			}
			fclose($fp);
			return $return;
		}else{
			return false;
		}
	}

	/**
	 * Strips newlines to prevent header injection.
	 * 
	 * @access private 
	 * @param string $str String
	 * @return string 
	 */
	function SecureHeader($str){
		$str = trim($str);
		$str = str_replace("\r", "", $str);
		$str = str_replace("\n", "", $str);
		return $str;
	}

	/**
	 * Set the private key file and password to sign the message.
	 * 
	 * @access public 
	 * @param string $key_filename Parameter File Name
	 * @param string $key_pass Password for private key
	 */
	function Sign($cert_filename, $key_filename, $key_pass){
		$this -> sign_cert_file = $cert_filename;
		$this -> sign_key_file = $key_filename;
		$this -> sign_key_pass = $key_pass;
	}
}

?>